package nl.utwente.ewi.hmi.multitouch;

public final class Resolution implements Comparable<Resolution> {

	public enum Measurement {
		DOTS_PER_INCH, DOTS_PER_CENTIMETER, MICROMETER_DOT_SPACING
	}

	private final double micrometerDotSpacing;

	public Resolution(double value, Measurement measurement) {
		this.micrometerDotSpacing = Resolution.getMicrometerDotSpacing(value, measurement);
	}

	public double getValue(Measurement measurement) {
		switch (measurement) {
		case MICROMETER_DOT_SPACING:
			return micrometerDotSpacing;
		case DOTS_PER_INCH:
			return this.getDotsPerInch();
		case DOTS_PER_CENTIMETER:
			return this.getDotsPerCentimeter();
		}

		throw new IllegalArgumentException("Measurement can not be null");
	}

	public double getDotsPerInch() {
		return getDotsPerInch(this.micrometerDotSpacing, Measurement.MICROMETER_DOT_SPACING);
	}

	public double getDotsPerCentimeter() {
		return getDotsPerCentimeter(this.micrometerDotSpacing, Measurement.MICROMETER_DOT_SPACING);
	}

	public double getMicrometerDotSpacing() {
		return this.micrometerDotSpacing;
	}

	public static double getDotsPerCentimeter(double value, Measurement measurement) {
		switch (measurement) {
			case MICROMETER_DOT_SPACING:
				return 10000d / value;
			case DOTS_PER_INCH:
				return value / 2.54d;
			case DOTS_PER_CENTIMETER:
				return value;
		}

		throw new IllegalArgumentException("Measurement can not be null");
	}

	public static double getDotsPerInch(double value, Measurement measurement) {
		switch (measurement) {
			case MICROMETER_DOT_SPACING:
				return 25400d / value;
			case DOTS_PER_INCH:
				return value;
			case DOTS_PER_CENTIMETER:
				return 2.54d * value;
		}

		throw new IllegalArgumentException("Measurement can not be null");
	}

	public static double getMicrometerDotSpacing(double value, Measurement measurement) {
		switch (measurement) {
			case MICROMETER_DOT_SPACING:
				return value;
			case DOTS_PER_INCH:
				return 25400d / value;
			case DOTS_PER_CENTIMETER:
				return 10000d / value;
		}

		throw new IllegalArgumentException("Measurement can not be null");
	}

	@Override
	public int compareTo(Resolution o) {
		return Double
				.compare(this.micrometerDotSpacing, o.micrometerDotSpacing);
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof Resolution)) {
			return false;
		}
		Resolution other = (Resolution) obj;

		return this.compareTo(other) == 0;
	}

	@Override
	public int hashCode() {
		return new Double(this.micrometerDotSpacing).hashCode();
	}

}
